package br.inf.mfpo.fra4and.activities;

import android.app.AlertDialog;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.AsyncQueryHandler;
import android.content.ComponentName;
import android.content.ContentUris;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.Toast;
import br.inf.mfpo.fra4and.R;

/**
 * Activity que implementa uma lista
 * 
 * @author MarcosFPo
 * 
 * @param <T>
 */
public abstract class Fra4AndListActivity<T extends SimpleCursorAdapter> extends ListActivity {
	protected final String TAG = getClass().getSimpleName();

	public static final int MENU_ITEM_EDIT = Menu.FIRST;
	public static final int MENU_ITEM_DELETE = Menu.FIRST + 1;
	public static final int MENU_ITEM_INSERT = Menu.FIRST + 2;

	/**
	 * Define o adapter da lista
	 * 
	 * @return
	 */
	protected abstract T buildAdapter();

	/**
	 * Define o título do menu de contexto
	 * 
	 * @param cursor
	 * @return
	 */
	protected abstract String getContextMenuTitle(Cursor cursor);

	/**
	 * Define a projeção do vetor que alimentará a lista
	 * 
	 * @return
	 */
	protected abstract String[] getProjection();

	/**
	 * Indica se é possível a exclusão
	 * 
	 * @return
	 */
	protected abstract boolean canDelete();

	/**
	 * Define a mensagem do diálogo de confirmação da exclusão
	 * 
	 * @param position
	 * @param selection
	 * @return
	 */
	protected abstract String getDeleteMessage(int position, Uri selection);

	/**
	 * Define a mensagem pós exclusão
	 * 
	 * @return
	 */
	protected abstract String getDeletedMessage();

	/**
	 * Define a mensagem em caso de erro na exclusão
	 * 
	 * @return
	 */
	protected abstract String getDeleteErrorMessage();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		Log.d(TAG, "Creating " + TAG);
		setContentView(R.layout.list_content);
		setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT);
		ListView list = getListView();
		list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
		list.setOnCreateContextMenuListener(this);
		setListAdapter(buildAdapter());
	}

	@Override
	protected void onResume() {
		getAsyncQuery().startQuery(0, null, getIntent().getData(), getProjection(), null, null, null);
		super.onResume();
	}

	@Override
	protected void onPause() {
		super.onPause();
	}

	protected void showNotification(int stringId) {
		Toast.makeText(getApplicationContext(), getString(stringId), Toast.LENGTH_SHORT).show();
	}

	protected void showNotification(String msg) {
		Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
	}

	protected ListAsyncQuery getAsyncQuery() {
		return new ListAsyncQuery(this);
	}

	private class ListAsyncQuery extends AsyncQueryHandler {
		private ProgressDialog pgdLoading;

		public ListAsyncQuery(Context context) {
			super(context.getContentResolver());
			pgdLoading = new ProgressDialog(context);
			pgdLoading.setIndeterminate(true);
			pgdLoading.setMessage(getString(R.string.loading));
		}

		@Override
		public void startQuery(int token, Object cookie, Uri uri, String[] projection, String selection, String[] selectionArgs, String orderBy) {
			pgdLoading.show();
			super.startQuery(token, cookie, uri, projection, selection, selectionArgs, orderBy);
		}

		@Override
		protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
			SimpleCursorAdapter adapter = (SimpleCursorAdapter) getListView().getAdapter();
			adapter.changeCursor(cursor);
			adapter.notifyDataSetChanged();
			if (pgdLoading.isShowing()) {
				pgdLoading.dismiss();
			}
			super.onQueryComplete(token, cookie, cursor);
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);

		MenuItem menuItem = menu.add(0, MENU_ITEM_INSERT, 0, R.string.menu_add);
		menuItem.setShortcut('3', 'a');
		menuItem.setIcon(android.R.drawable.ic_menu_add);

		Intent intent = new Intent(null, getIntent().getData());
		intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
		menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, new ComponentName(this, this.getClass()), null, intent, 0, null);

		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case MENU_ITEM_INSERT:
			startActivity(new Intent(Intent.ACTION_INSERT, getIntent().getData()));
			return true;
		}

		return super.onOptionsItemSelected(item);
	}

	@Override
	public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {

		AdapterView.AdapterContextMenuInfo info;
		try {
			info = (AdapterView.AdapterContextMenuInfo) menuInfo;
		} catch (ClassCastException e) {
			Log.e(getClass().getSimpleName(), "bad menuInfo", e);
			return;
		}

		Cursor cursor = (Cursor) getListAdapter().getItem(info.position);
		if (cursor == null) {
			return;
		}

		menu.setHeaderTitle(getContextMenuTitle(cursor));

		MenuItem mnuEdit = menu.add(1, MENU_ITEM_EDIT, 1, R.string.menu_edit);
		mnuEdit.setIcon(android.R.drawable.ic_menu_edit);

		MenuItem mnuDelete = menu.add(1, MENU_ITEM_DELETE, 2, R.string.menu_delete);
		mnuDelete.setIcon(android.R.drawable.ic_menu_delete);
	}

	@Override
	public boolean onContextItemSelected(MenuItem item) {
		AdapterView.AdapterContextMenuInfo info;
		try {
			info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
		} catch (ClassCastException e) {
			Log.e(getClass().getSimpleName(), "bad menuInfo", e);
			return false;
		}

		final long id = info.id;
		final int position = info.position;
		final Uri selection = ContentUris.withAppendedId(getIntent().getData(), id);

		switch (item.getItemId()) {
		case MENU_ITEM_DELETE:
			if (canDelete()) {
				delete(position, selection);
			}
			return true;
		case MENU_ITEM_EDIT:
			Intent edit = new Intent(Intent.ACTION_EDIT, selection);
			startActivity(edit);
			return true;
		}

		return false;
	}

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		super.onPrepareOptionsMenu(menu);
		final boolean haveItems = getListAdapter().getCount() > 0;
		if (haveItems) {
			Uri uri = ContentUris.withAppendedId(getIntent().getData(), getSelectedItemId());
			Intent[] specifics = new Intent[1];
			specifics[0] = new Intent(Intent.ACTION_EDIT, uri);
			MenuItem[] items = new MenuItem[1];

			Intent intent = new Intent(null, uri);
			intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
			menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, null, specifics, intent, 0, items);

			if (items[0] != null) {
				items[0].setShortcut('1', 'e');
			}
		} else {
			menu.removeGroup(Menu.CATEGORY_ALTERNATIVE);
		}

		return true;
	}

	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {
		Uri uri = ContentUris.withAppendedId(getIntent().getData(), id);

		String action = getIntent().getAction();
		if (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action)) {
			setResult(RESULT_OK, new Intent().setData(uri));
			finish();
		} else if (Intent.ACTION_VIEW.equals(action)) {
			startActivity(new Intent(Intent.ACTION_VIEW, uri));
		}
	}

	protected void delete(final int position, final Uri selection) {
		AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
		dialogBuilder.setTitle(android.R.string.dialog_alert_title);
		dialogBuilder.setMessage(getDeleteMessage(position, selection));
		dialogBuilder.setIcon(android.R.drawable.ic_dialog_alert);
		dialogBuilder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				onDoDeleteClick(position, selection);
			}
		});
		dialogBuilder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				onCancelDeleteClick();
			}
		});
		dialogBuilder.create().show();
	}

	protected void showDeleteErrorDialog(Exception e) {
		AlertDialog.Builder errorDialogBuilder = new AlertDialog.Builder(this);
		errorDialogBuilder.setTitle(android.R.string.dialog_alert_title);
		errorDialogBuilder.setMessage(getDeleteErrorMessage());
		errorDialogBuilder.setIcon(android.R.drawable.ic_dialog_alert);
		errorDialogBuilder.setNeutralButton(android.R.string.ok, null);
		errorDialogBuilder.create().show();
		if (e != null) {
			Log.d(getClass().getSimpleName(), e.getLocalizedMessage());
		}
	}

	protected void onDoDeleteClick(int position, Uri selection) {
		try {
			getContentResolver().delete(selection, null, null);
			showNotification(getDeletedMessage());
		} catch (Exception e) {
			showDeleteErrorDialog(e);
		}

	}

	protected void onCancelDeleteClick() {
		showNotification(br.inf.mfpo.fra4and.R.string.canceled);
	}
}
